package com.gitee.srurl.core.config;

import com.gitee.srurl.core.properties.ThreadPoolProperties;
import com.gitee.srurl.core.util.Threads;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author zxw
 * @date 2023/4/29 22:04
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ThreadPoolConfig {

    private final ThreadPoolProperties threadPoolProperties;

    private ThreadPoolExecutor threadPoolExecutor;

    private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    @Value("${short-url.thread-pool.scheduled-pool.core-pool-size}")
    private Integer scheduledCorePoolSize;

    @Bean(name = "threadPoolExecutor")
    public ThreadPoolExecutor threadPoolExecutor() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                threadPoolProperties.getCorePoolSize(),
                threadPoolProperties.getMaxPoolSize(),
                threadPoolProperties.getKeepAliveSeconds(),
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(threadPoolProperties.getQueueCapacity()),
                new BasicThreadFactory.Builder().namingPattern("su-thread-pool-%d").build(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );

        this.threadPoolExecutor = executor;
        return executor;
    }

    @Bean(name = "scheduledThreadPoolExecutor")
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor() {

        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(scheduledCorePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(false).build(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        this.scheduledThreadPoolExecutor = scheduledThreadPoolExecutor;
        return scheduledThreadPoolExecutor;
    }

    @PreDestroy
    private void destroy() {
        Threads.shutdownAndAwaitTermination(threadPoolExecutor);
        Threads.shutdownAndAwaitTermination(scheduledThreadPoolExecutor);
    }
}
